﻿/**	@file		matrix.h
 *	@date		(2006-06-19 23:33:35)/(2012-10-06 14:15:40)
 *-----------------------------------------------------------------------------
 *	\brief		矩阵.
 *	@version	1.0.7.11
 *	@author		Nick Shallery	(nicknide@gmail.com)
 *	@copyright	YOU HAVE ALL LEFT WITH THIS CODE WHILE YOU KEEP COMMENT IN EVERY COPY.
 *-----------------------------------------------------------------------------
**/


#if			!defined(__LOLIX__SOLA__MATRIX__K_IN_G__)
#define		__LOLIX__SOLA__MATRIX__K_IN_G__
#ifdef		__cplusplus


#if			!defined(__LOLIX__LOLI_X_CFG__K_IN_G__)
	#include	"../lolix_cfg.h"
#endif	//	!defined(__LOLIX__LOLI_X_CFG__K_IN_G__)


#if			!defined(__LOLIX__SOLA__VEC__NICK__K_IN_G__)
	#include	"./vec.hpp"
#endif	//	!defined(__LOLIX__SOLA__VEC__NICK__K_IN_G__)


//#include	"../code/main.h"
/////////////////////////////////////////////////////////////////////
//			this->v[0][0]	this->v[1][0]	this->v[2][0]	....	this->v[n-1][0]
//			this->v[0][1]	this->v[1][1]	this->v[2][1]	....	this->v[n-1][1]
//			this->v[0][2]	this->v[1][2]	this->v[2][2]	....	this->v[n-1][2]
//.....		....		....		....		....	....
//			this->v[0][n-1]	this->v[1][n-1]	this->v[2][n-1]	....	this->v[n-1][n-1]



template<lolix::size_type dim, typename v_type>
class lolix::sola::matrix
	: public lolix::sola::_help::matrix_base<dim, v_type>
{
	typedef _help::matrix_base<dim, v_type>	base_type;
	typedef matrix<dim, v_type>	this_type;
	typedef this_type&			this_ref;
	typedef const this_type&	this_const_ref;
public:
	matrix(void){}
	void identity(void)
	{
		for(unsigned int i = 0; i < dim; ++i)
		{
			unsigned int j;
			for(j = 0; j < i; ++j)	this->v[j][i] = v_type(0);
									this->v[j][i] = v_type(1);
			for(++j; j < dim; ++j)	this->v[j][i] = v_type(0);
		}
	}

	void transpose(void)
	{
		v_type tmp;
		for ( unsigned int i = 0; i < dim-1; ++i )
			for ( unsigned int j = i+1; j < dim; ++j )
			{
				tmp = this->v[i][j]; this->v[i][j] = this->v[j][i]; this->v[j][i] = tmp;
			}
	}

	this_ref operator *= (this_const_ref o)
	{
		transpose();
		this_type tmp(*this);
		for ( unsigned int i = 0; i < dim; ++i )
			for ( unsigned int j = 0; j < dim; ++j )
			{
				this->v[i][j] = tmp.v[i].dot(o.v[j]);
			}

		return *this;
	}

	this_type operator*(this_const_ref o)const
	{
		this_type tmp(*this);
		return tmp*= o;
	}

	vec<dim, v_type>& operator[](unsigned int pos)
	{ return this->v[pos]; }
	const vec<dim, v_type>& operator[](unsigned int pos)const
	{ return this->v[pos]; }

	vec<dim, v_type> v[dim];
};


template<typename v_type>
class lolix::sola::matrix<3, v_type>
	: public lolix::sola::_help::matrix_base<3, v_type>
{
	typedef _help::matrix_base<3, v_type>	base_type;
	typedef matrix<3, v_type>	this_type;
	typedef this_type&			this_ref;
	typedef const this_type&	this_const_ref;
public:
	void	identity(void)
	{
		this->v[0][0]=v_type(1);this->v[0][1]=v_type(0);this->v[0][2]=v_type(0);
		this->v[1][0]=v_type(0);this->v[1][1]=v_type(1);this->v[1][2]=v_type(0);
		this->v[2][0]=v_type(0);this->v[2][1]=v_type(0);this->v[2][2]=v_type(1);
	}

	void	transpose(void)
	{
		v_type tmp;
		tmp = this->v[0][1]; this->v[0][1] = this->v[1][0]; this->v[1][0] = tmp;
		tmp = this->v[0][2]; this->v[0][2] = this->v[2][0]; this->v[2][0] = tmp;
		tmp = this->v[1][2]; this->v[1][2] = this->v[2][1]; this->v[2][1] = tmp;
	}

	this_ref operator*=(this_const_ref o)
	{
		transpose();
		this_type tmp(*this);
		this->v[0][0] = tmp[0].dot(o.v[0]);
		this->v[0][1] = tmp[1].dot(o.v[0]);
		this->v[0][2] = tmp[2].dot(o.v[0]);

		this->v[1][0] = tmp[0].dot(o.v[1]);
		this->v[1][1] = tmp[1].dot(o.v[1]);
		this->v[1][2] = tmp[2].dot(o.v[1]);

		this->v[2][0] = tmp[0].dot(o.v[2]);
		this->v[2][1] = tmp[1].dot(o.v[2]);
		this->v[2][2] = tmp[2].dot(o.v[2]);

		return *this;
	}


	const this_type operator *(this_const_ref o)const
	{
		this_type tmp(*this);
		return tmp*=o;
	}


	const vec<3, v_type> operator * (const vec<3, v_type>& v3)const
	{
		vec<3, v_type> vtmp;
		vec<3, v_type> vret;
		vtmp(this->v[0][0], this->v[1][0], this->v[2][0]);
		vret[0] = vtmp.dot(v3);
		vtmp(this->v[0][1], this->v[1][1], this->v[2][1]);
		vret[1] = vtmp.dot(v3);
		vtmp(this->v[0][2], this->v[1][2], this->v[2][2]);
		vret[2] = vtmp.dot(v3);
		return vret;
	}

	vec<3, v_type>& operator[](unsigned int pos)
	{ return this->v[pos]; }
	const vec<3, v_type>& operator[](unsigned int pos)const
	{ return this->v[pos]; }

	vec<3, v_type>	v[3];
};


template<typename v_type>
class lolix::sola::matrix<4, v_type>
	: public lolix::sola::_help::matrix_base<4, v_type>
{
	typedef matrix<4, v_type>		this_type;
	typedef _help::matrix_base<4, v_type>	base_type;

	typedef	this_type&				this_ref;
	typedef const this_type&		this_const_ref;
public:
	matrix<4, v_type>(void){}
	matrix<4, v_type>(const matrix<4, v_type>& o)
	{
		*this = o;
	}

	matrix<4, v_type>& operator = (const matrix<4, v_type>& o)
	{
#define	_VCP_(x, y)	this->v[x][y] = o[x][y]
		_VCP_(0, 0);_VCP_(1, 0);_VCP_(2, 0);_VCP_(3, 0);
		_VCP_(0, 1);_VCP_(1, 1);_VCP_(2, 1);_VCP_(3, 1);
		_VCP_(0, 2);_VCP_(1, 2);_VCP_(2, 2);_VCP_(3, 2);
		_VCP_(0, 3);_VCP_(1, 3);_VCP_(2, 3);_VCP_(3, 3);
#undef	_VCP_
		return *this;
	}

	void identity(void)
	{
		this->v[0][0]=v_type(1);this->v[1][0]=v_type(0);this->v[2][0]=v_type(0);this->v[3][0]=v_type(0);
		this->v[0][1]=v_type(0);this->v[1][1]=v_type(1);this->v[2][1]=v_type(0);this->v[3][1]=v_type(0);
		this->v[0][2]=v_type(0);this->v[1][2]=v_type(0);this->v[2][2]=v_type(1);this->v[3][2]=v_type(0);
		this->v[0][3]=v_type(0);this->v[1][3]=v_type(0);this->v[2][3]=v_type(0);this->v[3][3]=v_type(1);
	}

	void transpose(void)
	{
		v_type tmp;
		tmp = this->v[0][1]; this->v[0][1] = this->v[1][0]; this->v[1][0] = tmp;
		tmp = this->v[0][2]; this->v[0][2] = this->v[2][0]; this->v[2][0] = tmp;
		tmp = this->v[0][3]; this->v[0][3] = this->v[3][0]; this->v[3][0] = tmp;

		tmp = this->v[1][2]; this->v[1][2] = this->v[2][1]; this->v[2][1] = tmp;
		tmp = this->v[1][3]; this->v[1][3] = this->v[3][1]; this->v[3][1] = tmp;

		tmp = this->v[2][3]; this->v[2][3] = this->v[3][2]; this->v[3][2] = tmp;
	}

	this_ref operator*=(this_const_ref o)
	{
		transpose();
		this_type tmp(*this);
		this->v[0][0] = tmp[0].dot(o.v[0]);
		this->v[0][1] = tmp[1].dot(o.v[0]);
		this->v[0][2] = tmp[2].dot(o.v[0]);
		this->v[0][3] = tmp[3].dot(o.v[0]);

		this->v[1][0] = tmp[0].dot(o.v[1]);
		this->v[1][1] = tmp[1].dot(o.v[1]);
		this->v[1][2] = tmp[2].dot(o.v[1]);
		this->v[1][3] = tmp[3].dot(o.v[1]);

		this->v[2][0] = tmp[0].dot(o.v[2]);
		this->v[2][1] = tmp[1].dot(o.v[2]);
		this->v[2][2] = tmp[2].dot(o.v[2]);
		this->v[2][3] = tmp[3].dot(o.v[2]);

		this->v[3][0] = tmp[0].dot(o.v[3]);
		this->v[3][1] = tmp[1].dot(o.v[3]);
		this->v[3][2] = tmp[2].dot(o.v[3]);
		this->v[3][3] = tmp[3].dot(o.v[3]);

		return *this;
	}

	//	行列式的值: 好像有问题
	//v_type	det(void)const
	//{
	//	v_type val =
	//		   this->v[0][0]*this->v[1][1]*this->v[2][2]*this->v[3][3];
	//	val += this->v[1][0]*this->v[2][1]*this->v[3][2]*this->v[0][3];
	//	val += this->v[2][0]*this->v[3][1]*this->v[0][2]*this->v[1][3];
	//	val += this->v[3][0]*this->v[0][1]*this->v[1][2]*this->v[2][3];
	//	val -= this->v[0][0]*this->v[3][1]*this->v[2][2]*this->v[1][3];
	//	val -= this->v[1][0]*this->v[0][1]*this->v[3][2]*this->v[2][3];
	//	val -= this->v[2][0]*this->v[1][1]*this->v[0][2]*this->v[3][3];
	//	val -= this->v[3][0]*this->v[2][1]*this->v[1][2]*this->v[0][3];
	//	return val;
	//}

	this_type operator *(this_const_ref o)const
	{
		this_type tmp(*this);
		return tmp*=o;
	}

	vec<4, v_type> operator * (vec<4, v_type>& v4)const
	{
		vec<4, v_type> vtmp;
		vec<4, v_type> vret;
		vtmp(this->v[0][0], this->v[1][0], this->v[2][0], this->v[3][0]);
		vret[0] = vtmp.dot(v4);
		vtmp(this->v[0][1], this->v[1][1], this->v[2][1], this->v[3][1]);
		vret[1] = vtmp.dot(v4);
		vtmp(this->v[0][2], this->v[1][2], this->v[2][2], this->v[3][2]);
		vret[2] = vtmp.dot(v4);
		vtmp(this->v[0][3], this->v[1][3], this->v[2][3], this->v[3][3]);
		vret[3] = vtmp.dot(v4);
		return vret;
	}

	vec<4, v_type>& operator[](unsigned int pos)
	{ return this->v[pos]; }
	const vec<4, v_type>& operator[](unsigned int pos)const
	{ return this->v[pos]; }

	this_ref	operator /= (v_type v)
	{
		for ( size_type i = 0; i != 4; ++i )
		{
			this->v[i][0] /= v;
			this->v[i][1] /= v;
			this->v[i][2] /= v;
			this->v[i][3] /= v;
		}

		return *this;
	}

	vec<4, v_type>	v[4];
};


namespace	lolix{
	namespace sola{
		typedef	matrix<2, float>	mat2;
		typedef	matrix<3, float>	mat3;
		typedef	matrix<4, float>	mat4;

		typedef	matrix<2, double>	dmat2;
		typedef	matrix<3, double>	dmat3;
		typedef	matrix<4, double>	dmat4;
	}
}

#else	//	__cplusplus
#	error	Must Have C++ Complier Support
#endif	//	__cplusplus

#endif	//	!defined(__LOLIX__SOLA__MATRIX__K_IN_G__)
